home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / vopts / gadgets.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  47KB  |  1,218 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6. #include "vopts.h"
  7.  
  8. Prototype int  init_gadgets(void);
  9. Prototype void free_gadget(struct Gadget *gadget);
  10. Prototype void free_gadlist(struct GADLIST *gadlist);
  11. Prototype int  set_group_gadgets(void);
  12. Prototype void set_fr_gadgets(char *frtext);
  13. Prototype void clear_fr_gadgets(void);
  14. Prototype struct Gadget *create_gadget(struct GADLIST *gadlist,struct G_OBJECT *object,int ulx, int uly,int width);
  15. Prototype void setup_string_gadget(struct Gadget *gad,int base);
  16. Prototype struct Gadget *setup_cycle_gadget(struct Gadget *gad,struct IntuiText *itext,struct G_VALUE *val);
  17. Prototype void reset_list_object(struct G_LIST *list,int active);
  18. Prototype int  setup_list_object(struct GADLIST *gadlist,struct Gadget *gad);
  19. Prototype struct GADLIST *layout_gadgets(struct G_OBJECT *objlist, int group, int ulx, int uly, int width);
  20. Prototype struct Border *build_border(int width, int height, int mode);
  21. Prototype int  init_gad_sizes(void);
  22. Prototype void get_cycle_sizes(struct G_OBJECT *objlist, int *titsize,  int *cycsize, int *fudgesize);
  23. Prototype int  text_width(char *str);
  24. Prototype int string_width(char *str, int def_size);
  25.  
  26. /***********************************************************************************
  27.  * Procedure: init_gadgets
  28.  * Synopsis:  rc = init_gadgets();
  29.  * Purpose:   Set up all the base system gadgets for the window.  This includes all
  30.  *            The user defined gadgets as well as the three buttons on the bottom
  31.  ***********************************************************************************/
  32. int init_gadgets()
  33. {
  34.    struct Gadget *gad;
  35.    struct Border *border;
  36.    struct IntuiText *itext;
  37.    int ulx, uly;
  38.    int i;
  39.  
  40.    global.gadlist = layout_gadgets(global.objects, 0,
  41.                                     global.ri.WindowLeft,
  42.                                     global.ri.WindowTitle,
  43.                                     global.cycsize[0]+global.titsize[0]
  44.                                     );
  45.    if (global.gadlist == NULL) return(1);
  46.    ulx = global.ri.WindowLeft;
  47.    uly = global.height - global.ri.WindowBottom - global.iheight;
  48.  
  49.    for(i = 0; i < 3; i++)
  50.    {
  51.       global.button[i].class = CLASS_BUTTON;
  52.       global.button[i].state = i; /* Note that these values correspond to */
  53.                                    /* the BUTTON_xxx equates               */
  54.  
  55.       gad = create_gadget(NULL, global.button+i, ulx, uly, BUTTON_WIDTH);
  56.  
  57.       if (gad == NULL) return(1);
  58.       gad->GadgetRender = build_border(BUTTON_WIDTH,
  59.                                        global.iheight, MODE_OUT);
  60.  
  61.       itext = gad->GadgetText;
  62.       itext->LeftEdge += (BUTTON_WIDTH - IntuiTextLength(itext))/2;
  63.  
  64.       gad->NextGadget = global.gadlist->gadgets;
  65.       global.gadlist->gadgets = gad;
  66.       global.gadlist->count++;
  67.  
  68.       gad->GadgetType = BOOLGADGET;
  69.  
  70.       ulx += (global.width - (global.ri.WindowLeft  +
  71.                                global.ri.WindowRight +
  72.                                (3*BUTTON_WIDTH)
  73.                               )
  74.              ) / 2 + BUTTON_WIDTH;
  75.    }
  76.  
  77.    /* Calculate the limits for the box that holds the gadgets */
  78.    global.boxw = global.cycsize[1] + global.titsize[1] +
  79.                   MARGIN_LEFT + MARGIN_RIGHT;
  80.    global.boxx = global.width - global.ri.WindowRight - global.boxw;
  81.  
  82.    global.boxy = global.ri.WindowTitle + DHBAR;
  83.    global.boxh = uly - MARGIN_MID - DVBAR - global.boxy;
  84.  
  85.    for (i = 2; i >= 0; i -= 2)
  86.    {
  87.       /* We also need to attach a box around the other area.  Since we don't want to */
  88.       /* Have to constantly create/recreate it, we can get away with putting it on   */
  89.       /* the first button.                                                           */
  90.       border = build_border(global.boxw + DVBAR + i*2,
  91.                             global.boxh + DHBAR + i,
  92.                             i ? MODE_IN : MODE_OUT);
  93.       if (border != NULL)
  94.       {
  95.          border->NextBorder->LeftEdge =
  96.          border->LeftEdge = (global.boxx - VBAR - i       ) - gad->LeftEdge;
  97.          border->NextBorder->TopEdge =
  98.          border->TopEdge  = (global.boxy - HBAR - (i >> 1)) - gad->TopEdge;
  99.          border->NextBorder->NextBorder = gad->GadgetRender;
  100.          gad->GadgetRender = border;
  101.       }
  102.    }
  103.  
  104.    global.boxx += MARGIN_LEFT;
  105.    global.boxy += MARGIN_TOP-DHBAR;
  106.    global.boxw -= (MARGIN_LEFT+MARGIN_RIGHT);
  107.    global.boxh -= (MARGIN_TOP-DHBAR+MARGIN_BOTTOM);
  108.  
  109.    /* now setup stuff for default file requester gadgets */
  110.    for (i = 0; i < 2; i++)
  111.    {
  112.       global.frbutton[i].class = CLASS_BUTTON;
  113.       global.frbutton[i].state = BUTTON_FRSAVE + i;
  114.       /* this is a shameless trick to skip the normal middle button */
  115.       global.frbutton[i].title = global.button[2*i].title;
  116.  
  117.       global.frbutton[i].title =
  118.          global.text[i == 0 ? TEXT_OK : TEXT_CANCEL];
  119.    }
  120.    global.frstring.base.class = CLASS_STRING;
  121.    global.frstring.base.title = global.text[TEXT_FILEREQ];
  122.  
  123.    return(set_group_gadgets());
  124. }
  125. /***********************************************************************************
  126.  * Procedure: free_gadget
  127.  * Synopsis:  free_gadget(gadget)
  128.  * Purpose:   Free up all memory associated with a gadget
  129.  ***********************************************************************************/
  130. void free_gadget(struct Gadget *gadget)
  131. {
  132.    struct G_OBJECT *obj;
  133.  
  134.    if (gadget)
  135.    {
  136.       obj = (struct G_OBJECT *)(gadget->UserData);
  137.  
  138.       obj->gadget = NULL;
  139.  
  140.       if (obj->class == CLASS_STRING)
  141.       {
  142.          /* We need to free the border structure also */
  143.       }
  144.       free_mem(gadget, sizeof(struct Gadget)+sizeof(struct IntuiText));
  145.    }
  146. }
  147.  
  148. /***********************************************************************************
  149.  * Procedure: free_gadlist
  150.  * Synopsis:  free_gadlist(gadlist)
  151.  * Purpose:   Free up all memory associated with a gadget list created by
  152.  *            layout_gadgets
  153.  ***********************************************************************************/
  154. void free_gadlist(struct GADLIST *gadlist)
  155. {
  156.    struct Gadget *gad, *nextgad;
  157.    struct G_CYCLE *cyc;
  158.    struct G_STRING *str;
  159.  
  160.    for(gad = gadlist->gadgets; gad && gadlist->count; gad = nextgad, gadlist->count--)
  161.    {
  162.       nextgad = gad->NextGadget;
  163.       cyc = (struct G_CYCLE *)gad->UserData;
  164.  
  165.       if (cyc->base.class == CLASS_CYCLE)
  166.       {
  167.          /* If there is a string gadget currently in the cycle gadget, we need */
  168.          /* to free it up                                                      */
  169.          if ((str = cyc->curval->string) != NULL)
  170.          {
  171.             free_gadget(str->base.gadget);
  172.          }
  173.       }
  174.       free_gadget(gad);
  175.    }
  176.  
  177.    free_mem(gadlist, sizeof(struct GADLIST));
  178. }
  179.  
  180. /***********************************************************************************
  181.  * Procedure: set_group_gadgets
  182.  * Synopsis:  set_group_gadgets();
  183.  * Purpose:   Create the gadgetry for
  184.  ***********************************************************************************/
  185. int set_group_gadgets()
  186. {
  187.    struct G_OBJECT *next;
  188.  
  189.    if (global.grpgadlist)
  190.    {
  191.       /* We need to take this off the system gadget list and then free up */
  192.       /* all the storage associated with it                               */
  193.       set_gadlist(global.grpgadlist, 0);
  194.       free_gadlist(global.grpgadlist);
  195.  
  196.       global.grpgadlist = NULL;
  197.    }
  198.  
  199.    if (global.rp)
  200.    {
  201.       /* Wipe out the inner area of the gadget so that we can redraw it later */
  202.       SetBPen(global.rp, 0);
  203.       SetAPen(global.rp, 0);
  204.       RectFill( global.rp, global.boxx, global.boxy,
  205.                             global.boxx+global.boxw, global.boxy+global.boxh);
  206.    }
  207.  
  208.    next = global.curgroup->base.next;
  209.    global.curgroup->base.next = global.curgroup->objects;
  210.    global.grpgadlist = layout_gadgets((struct G_OBJECT *)global.curgroup, 1,
  211.                                     global.boxx, global.boxy, global.boxw);
  212.    global.curgroup->base.next = next;
  213.  
  214.    set_gadlist(global.grpgadlist, 1);
  215.  
  216.    return(0);
  217. }
  218.  
  219. /***********************************************************************************
  220.  * Procedure: set_fr_gadgets
  221.  * Synopsis:  set_fr_gadgets(text);
  222.  * Purpose:   setup the string gadget and buttons for the default file requester
  223.  *            to use when AmigaDos 2.0 is not present.  Text is initial string
  224.  *            gadget text
  225.  ***********************************************************************************/
  226.  
  227. void set_fr_gadgets(char *frtext)
  228. {
  229.    int ulx, uly, i;
  230.    struct Gadget *gad;
  231.    struct IntuiText *itext;
  232.  
  233.    /* Need to see if requester already displayed an exit if so.  */
  234.    if (global.frgadlist != NULL) return;
  235.  
  236.    set_gadgets(0);
  237.    SetBPen(global.rp, 0);
  238.    SetAPen(global.rp, 0);
  239.    RectFill( global.rp, global.ri.WindowLeft,
  240.                         global.ri.WindowTitle,
  241.                         global.width - global.ri.WindowRight + 4,
  242.                         global.height - global.ri.WindowBottom);
  243.  
  244.    strncpy(global.frstring.buf, frtext, MAX_STRING);
  245.    /* make sure string is null terminated */
  246.    global.frstring.buf[MAX_STRING-1] = 0;
  247.    global.frgadlist = layout_gadgets((struct G_OBJECT *)&global.frstring, 2,
  248.                  global.ri.WindowLeft,
  249.                  global.ri.WindowTop + (global.height - global.iheight)/2,
  250.                  global.width);
  251.  
  252.    if (global.frgadlist == NULL) return;
  253.  
  254.    ulx = global.ri.WindowLeft;
  255.    uly = global.height - global.ri.WindowBottom - global.iheight;
  256.  
  257.    /* Create the buttons here */
  258.    for(i = 0; i < 2; i++)
  259.    {
  260.       gad = create_gadget(global.frgadlist, global.frbutton+i,
  261.                           ulx, uly, BUTTON_WIDTH);
  262.  
  263.       if (gad == NULL) return;
  264.       gad->GadgetRender = build_border(BUTTON_WIDTH,
  265.                                        global.iheight, MODE_OUT);
  266.  
  267.       itext = gad->GadgetText;
  268.       itext->LeftEdge += (BUTTON_WIDTH - IntuiTextLength(itext))/2;
  269.  
  270.       gad->GadgetType = BOOLGADGET;
  271.       ulx = global.width - (global.ri.WindowRight + BUTTON_WIDTH);
  272.    }
  273.    set_gadlist(global.frgadlist, 1);
  274.  
  275. }
  276.  
  277. /***********************************************************************************
  278.  * Procedure: clear_fr_gadgets
  279.  * Synopsis:  clear_fr_gadgets();
  280.  * Purpose:   remove the default requester stuff and redisplay the normal
  281.  *            VOPTS gadgets.
  282.  ***********************************************************************************/
  283.  
  284. void clear_fr_gadgets(void)
  285. {
  286.    if (global.frgadlist != NULL)
  287.    {
  288.       set_gadlist(global.frgadlist, 0);
  289.       /* Free the gadlist */
  290.       free_gadlist(global.frgadlist);
  291.       global.frgadlist = NULL;
  292.       SetBPen(global.rp, 0);
  293.       SetAPen(global.rp, 0);
  294.       RectFill( global.rp, global.ri.WindowLeft,
  295.                         global.ri.WindowTitle,
  296.                         global.width - global.ri.WindowRight,
  297.                         global.height - global.ri.WindowBottom);
  298.  
  299.    }
  300.    set_gadgets(1);
  301.  
  302. }
  303. /***********************************************************************************
  304.  * Procedure: create_gadget
  305.  * Synopsis:  Gadget = create_gadget(gadlist, object, ulx, uly, width)
  306.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  307.  *            of gadgets.
  308.  ***********************************************************************************/
  309. struct Gadget *create_gadget(struct GADLIST *gadlist,
  310.                              struct G_OBJECT *object,
  311.                              int ulx, int uly,
  312.                              int width
  313.                             )
  314. {
  315.    struct Gadget *gad;
  316.    struct IntuiText *itext;
  317.  
  318.  
  319.    /* Create a gadget structure and an associated intuitext structure to be */
  320.    /* Layed out on the screen                                               */
  321.    gad = (struct Gadget *)get_mem(sizeof(struct Gadget)+sizeof(struct IntuiText));
  322.    if (gad)
  323.    {
  324.       itext = (struct IntuiText *)(gad+1);
  325.  
  326.       gad->LeftEdge    = ulx;
  327.       gad->TopEdge     = uly;
  328.       gad->Width       = width;
  329.       gad->Height      = global.iheight;
  330.       gad->Flags       = GADGHCOMP;
  331.       gad->Activation  = RELVERIFY;
  332.       gad->GadgetText  = itext;
  333.       gad->UserData    = (APTR)object;
  334.       gad->GadgetID    = object->class;
  335.       object->gadget      = gad;
  336.  
  337.       /* Now we fill in the Intuitext structure */
  338.       itext->FrontPen  = 1;
  339.       itext->BackPen   = 0;
  340.       itext->DrawMode  = JAM1;
  341.       itext->LeftEdge  = 0;
  342.       itext->TopEdge   = (global.iheight - global.ri.FontSize) / 2;
  343.       itext->ITextFont = &global.ri.TextAttr;
  344.       itext->IText     = object->title;
  345.       itext->NextText  = NULL;
  346.  
  347.       if (gadlist)
  348.       {
  349.          gad->NextGadget = gadlist->gadgets;
  350.          gadlist->gadgets = gad;
  351.          gadlist->count++;
  352.       }
  353.    }
  354.  
  355.    return(gad);
  356. }
  357.  
  358. /***********************************************************************************
  359.  * Procedure: setup_string_gadget
  360.  * Synopsis:  setup_string_gadget(gad, string, ulx, uly, width, base)
  361.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  362.  *            of gadgets.
  363.  ***********************************************************************************/
  364. void setup_string_gadget(struct Gadget *gad,
  365.                          int base
  366.                         )
  367. {
  368.    int wraps;
  369.    int i;
  370.    struct Border *border;
  371.    struct StringInfo *si;
  372.    int sluff;
  373.  
  374.    if (gad == NULL) return;
  375.  
  376.    wraps = (base == CLASS_STRING) ? 2 : 1;
  377.  
  378.    gad->LeftEdge += VBAR*wraps;
  379.    gad->TopEdge  += DHBAR;
  380.    gad->Width    -= DVBAR*wraps;
  381.    gad->Height   -= 2*DHBAR;
  382.  
  383.    sluff = (gad->Height - global.ri.FontSize);
  384.    if (sluff < 0) sluff = 0;
  385.    gad->Height  = global.ri.FontSize;
  386.    gad->TopEdge += sluff / 2;
  387.    if (gad->GadgetText)
  388.    {
  389.       gad->GadgetText->TopEdge -= (DHBAR+sluff);
  390.       gad->GadgetText->LeftEdge -= VBAR*wraps;
  391.    }
  392.  
  393.    if ((base == CLASS_LIST)   ||
  394.        (base == CLASS_STRING) ||
  395.        (base == CLASS_CYCLE))
  396.    {
  397.       for(i=wraps; i > 0; i--)
  398.       {
  399.          /* We need to put a border around the gadget. */
  400.          /* For some string gadgets, we only need a single border */
  401.          /* We can tell this by the base type */
  402.          border = build_border(gad->Width+4*i, gad->Height + sluff + 2*i,
  403.                                (i == 1) ? MODE_IN : MODE_OUT);
  404.          if (border != NULL)
  405.          {
  406.             border->NextBorder->LeftEdge = border->LeftEdge = -2*i;
  407.             border->NextBorder->TopEdge  = border->TopEdge  = -1*i - (sluff/2);
  408.             border->NextBorder->NextBorder = gad->GadgetRender;
  409.             gad->GadgetRender = border;
  410.          }
  411.       }
  412.    }
  413.  
  414.    /* Lastly, we need to setup up the SpecialInfo structure for the string gadget */
  415.    /* If for some reason this fails, we will turn it into a button gadget         */
  416.    si = (struct StringInfo *)get_mem(sizeof(struct StringInfo));
  417.    if (si != NULL)
  418.    {
  419.       gad->SpecialInfo = (APTR)si;
  420.       gad->GadgetType = STRGADGET;
  421.       si->Buffer = ((struct G_STRING *)(gad->UserData))->buf;
  422.       si->MaxChars = MAX_STRING;
  423.    }
  424.    else
  425.       gad->GadgetType = BOOLGADGET;
  426. }
  427.  
  428.  
  429. /***********************************************************************************
  430.  * Procedure: setup_cycle_gadget
  431.  * Synopsis:  gadget = setup_cycle_gadget(gadget, value)
  432.  * Purpose:   Create any subtending string gadgets and correctly position any
  433.  *            cycle value text
  434.  ***********************************************************************************/
  435. struct Gadget *setup_cycle_gadget(struct Gadget *gad,
  436.                                   struct IntuiText *itext,
  437.                                   struct G_VALUE *val
  438.                                  )
  439. {
  440.    struct Gadget *strgad;
  441.    int ilen;
  442.  
  443.    ilen = IntuiTextLength(itext);
  444.  
  445.    if (val->string)
  446.    {
  447.       int x, width;
  448.  
  449.       itext->LeftEdge = CYC_ICON_WIDTH + 2;
  450.       /* We need to create a string gadget to get the input text from */
  451.  
  452.       x = itext->LeftEdge + ilen;
  453.       width = gad->Width - x - 2;
  454.  
  455.       /* Now, create a string gadget and border to put around the gadget */
  456.       strgad = create_gadget(NULL, (struct G_OBJECT *)val->string,
  457.                                        gad->LeftEdge+x, gad->TopEdge, width);
  458.       if (strgad)
  459.       {
  460.          setup_string_gadget(strgad, CLASS_CYCLE);
  461.       }
  462.    }
  463.    else
  464.    {
  465.       strgad = NULL;
  466.       itext->LeftEdge  = (CYC_ICON_WIDTH + gad->Width - ilen) / 2;
  467.    }
  468.    return(strgad);
  469. }
  470. /***********************************************************************************
  471.  * Procedure: reset_list_object
  472.  * Synopsis:  void reset_list_object(list,active);
  473.  * Purpose:   Initialize all the appropriate text pointers for a list gadget
  474.  ***********************************************************************************/
  475. void reset_list_object(struct G_LIST *list,
  476.                        int active
  477.                       )
  478. {
  479.    struct G_ENTRY *ent;
  480.    int i;
  481.  
  482.    ent = list->top;
  483.  
  484.    /* Run through all the entries visible on the screen and for each */
  485.    /* one that is displayed, mark the gadget as selectable.          */
  486.    for(i = 0; i < MAX_LIST; i++)
  487.    {
  488.       list->btngad[i]->Flags  = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  489.                                 GADGHNONE;
  490.       list->btngad[i]->Height = global.eheight;
  491.       list->strgad[i]->GadgetRender = NULL;
  492.       /* seems unnecessary, but Dos 1.3 likes to write blanks to unselected */
  493.       /* string gadgets                                                     */
  494.       ((struct StringInfo *)list->strgad[i]->SpecialInfo)->Buffer = global.defbuf;
  495.  
  496.       /* Is there an entry corresponding to this position on the screen? */
  497.       if (ent)
  498.       {
  499.          /* Certainly is an entry, is it where they want a string gadget ? */
  500.          if (i == active)
  501.          {
  502.             /* Yes, shrink the gadget out of existence so that it doesn't  */
  503.             /* appear on the screen.                                       */
  504.             list->btngad[i]->Height = 1;
  505.             list->strgad[i]->GadgetRender = list->sborder;
  506.          }
  507.          else
  508.          {
  509.             list->btngad[i]->Flags = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  510.                                      GADGHCOMP;
  511.          }
  512.  
  513.          ((struct StringInfo *)
  514.           list->strgad[i]->SpecialInfo)->Buffer = ent->buf;
  515.          ent = (struct G_ENTRY *)ent->base.next;
  516.       }
  517.    }
  518. }
  519.  
  520. /***********************************************************************************
  521.  * Procedure: setup_list_object
  522.  * Synopsis:  ulx = setup_list_object(gadlist, gadget)
  523.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  524.  *            object
  525.  ***********************************************************************************/
  526. int setup_list_object(struct GADLIST *gadlist,
  527.                       struct Gadget *gad
  528.                      )
  529. {
  530.    int ulx, uly, alen, dlen, ilen;
  531.    struct G_LIST *list;
  532.    int i;
  533.    char *savetitle;
  534.    struct Gadget *slider, *dngad, *upgad, *addgad, *delgad;
  535.    struct PropInfo *pi;
  536.  
  537. #define ARR_HEIGHT  (7+DHBAR)
  538. #define PROP_WIDTH  (14+DVBAR)
  539.  
  540.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  541.    /* A list object consists of 8 separate gadgets arranged as below*/
  542.    /* 1: Boolean gadgets that overlay string gadgets.  When the     */
  543.    /* 2:   string gadget is to be active, the height of the boolean */
  544.    /* 3:   gadget is set to 1 exposing the string gadget.           */
  545.    /* 4: A slider gadget to allow positioning in the list           */
  546.    /* 5: An up arrow gadget for moving up one item in the list      */
  547.    /* 6: A Down arrow gadget for moving down one item in the list   */
  548.    /* 7: A NEW gadget for creating an entry in front of current item*/
  549.    /* 8: A DEL gadget for removing the current item from the list.  */
  550.    /*                                                               */
  551.    /*                                                               */
  552.    /*  TITLE TEXT                                                   */
  553.    /* ............................................}+---+            */
  554.    /* ::+---------------------------------------+}}|4  |            */
  555.    /* ::|1                                      |}}|   |            */
  556.    /* ::| I T E M 1                             |}}|   |            */
  557.    /* ::+---------------------------------------+}}| _ |+-------+   */
  558.    /* ::+---------------------------------------+}}|[_]||7      |   */
  559.    /* ::|2                                      |}}|   || N E W |   */
  560.    /* ::| I T E M 2                             |}}+---+|       |   */
  561.    /* ::+---------------------------------------+}}|5^ |+-------+   */
  562.    /* ::+---------------------------------------+}}|/ \|+-------+   */
  563.    /* ::|3                                      |}}+---+|8      |   */
  564.    /* ::| I T E M 3                             |}}|\ /|| D E L |   */
  565.    /* ::+---------------------------------------+}}|6V ||       |   */
  566.    /* :}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}+---++-------+   */
  567.    /*                                                               */
  568.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  569.    list = (struct G_LIST *)gad->UserData;
  570.  
  571.    /* We need to figure out how big the NEW and DEL gadgets will be */
  572.    alen = ilen = text_width(global.button[BUTTON_NEW].title);
  573.    dlen = text_width(global.button[BUTTON_DEL].title);
  574.    if (dlen > ilen) ilen = dlen;
  575.    ilen += 2*DHBAR;
  576.  
  577.    gad->GadgetText->TopEdge   = -global.ri.FontSize;
  578.    gad->TopEdge     += global.ri.FontSize;
  579.    gad->Width       -= ilen + PROP_WIDTH;
  580.    gad->Height       = MAX_LIST*global.eheight + global.listextra;
  581.    gad->Flags        = GADGHNONE;
  582.    gad->GadgetRender = build_border(gad->Width,
  583.                                     gad->Height,
  584.                                     MODE_OUT);
  585.  
  586.    savetitle = list->base.title;
  587.    list->base.title = "";
  588.  
  589.    uly = gad->TopEdge;
  590.    ulx = gad->LeftEdge + gad->Width;
  591.  
  592.    /* Create the slider and two arrow gadgets.  We will steal the  */
  593.    /* first itext structure and throw it on to the main gadget     */
  594.    slider = create_gadget(gadlist, (struct G_OBJECT *)list,
  595.                                   ulx+DVBAR, uly+DHBAR, PROP_WIDTH-2*DVBAR );
  596.    if (slider == NULL) return(0);
  597.    list->slider = slider;
  598.    slider->Height       = global.listextra + MAX_LIST*global.eheight -
  599.                           2*ARR_HEIGHT - 2*DHBAR;
  600.    slider->GadgetID     = CLASS_PROP;
  601.    slider->GadgetType   = PROPGADGET;
  602.    pi = (struct PropInfo *)get_mem(sizeof(struct PropInfo)+
  603.                                            sizeof(struct Image));
  604.    if (pi == NULL) return(0);
  605.    slider->GadgetRender = (struct Image *)(pi+1);
  606.    slider->SpecialInfo  = (APTR)pi;
  607.    pi->Flags = AUTOKNOB | FREEVERT | PROPBORDERLESS;
  608.    recalc_prop(list, &pi->VertBody, &pi->VertPot);
  609.  
  610.    upgad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  611.                                   ulx, uly+slider->Height+2*DHBAR, PROP_WIDTH);
  612.    if (upgad == NULL) return(0);
  613.    upgad->Height       = ARR_HEIGHT;
  614.    upgad->GadgetRender = &global.arrowborder[1];
  615.    upgad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  616.    upgad->GadgetID     = CLASS_UP;
  617.    upgad->GadgetText   = NULL;
  618.  
  619.    dngad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  620.                                   ulx, upgad->TopEdge+ARR_HEIGHT, PROP_WIDTH);
  621.    if (dngad == NULL) return(0);
  622.    dngad->Height       = ARR_HEIGHT;
  623.    dngad->GadgetRender = &global.arrowborder[0];
  624.    dngad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  625.    dngad->GadgetID     = CLASS_DOWN;
  626.    dngad->GadgetText   = NULL;
  627.  
  628.    /* Create the ADD/DEL Buttons                                        */
  629.    addgad = create_gadget(gadlist, (struct G_OBJECT *)list, ulx+PROP_WIDTH,
  630.                                   uly + global.listextra + MAX_LIST*global.eheight-2*global.iheight, ilen);
  631.    if (addgad == NULL) return(0);
  632.    addgad->GadgetRender = build_border(ilen, addgad->Height, MODE_OUT);
  633.    addgad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  634.    addgad->GadgetID     = CLASS_ADD;
  635.    addgad->GadgetText->LeftEdge += (ilen-alen)>>1;
  636.    addgad->GadgetText->IText = global.button[BUTTON_NEW].title;
  637.  
  638.    delgad = create_gadget(gadlist, (struct G_OBJECT *)list, addgad->LeftEdge,
  639.                                        addgad->TopEdge+addgad->Height, ilen);
  640.    if (delgad == NULL) return(0);
  641.    list->delgad = delgad;
  642.    delgad->GadgetRender = addgad->GadgetRender;
  643.    delgad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  644.    delgad->GadgetID     = CLASS_DEL;
  645.    if (list->first == NULL)
  646.       delgad->Flags       |= GADGDISABLED;
  647.    delgad->GadgetText->LeftEdge += (ilen-dlen)>>1;
  648.    delgad->GadgetText->IText = global.button[BUTTON_DEL].title;
  649.  
  650.    for(i = 0; i < MAX_LIST; i++)
  651.    {
  652.       struct Gadget *tgad;
  653.  
  654.       /* Create the string and button gadgets.  Because we insert them on the */
  655.       /* List in reverse order and we want the button gadget to appear first, */
  656.       /* we need to create them in reverse order.                             */
  657.       /* This ordering is assumed in the state changing code.                 */
  658.       tgad = list->strgad[i] = create_gadget(gadlist,
  659.                                              (struct G_OBJECT *)list,
  660.                                              gad->LeftEdge+VBAR, uly,
  661.                                              gad->Width-DVBAR);
  662.       if (tgad == NULL) return(0);
  663.       tgad->GadgetText = NULL;
  664.       tgad->Height = global.eheight;
  665.       setup_string_gadget(tgad, CLASS_LIST+i);
  666.       tgad->GadgetID   = CLASS_STRING;
  667.  
  668.       tgad = list->btngad[i] = create_gadget(gadlist,
  669.                                              (struct G_OBJECT *)list,
  670.                                              gad->LeftEdge+VBAR, uly,
  671.                                              gad->Width-DVBAR);
  672.       if (tgad == NULL) return(0);
  673.       tgad->GadgetType = BOOLGADGET; /* not auto default for Dos 1.3  */
  674.       tgad->Height     = global.eheight;
  675.       tgad->GadgetText = NULL;
  676.       tgad->GadgetID   = CLASS_LIST+i;
  677.       uly += global.eheight;
  678.    }
  679.  
  680.    list->sborder = list->strgad[0]->GadgetRender;
  681.    list->strgad[0]->GadgetRender = NULL;
  682.  
  683.    /* Undo the damage we did to the base object */
  684.    list->base.title = savetitle;
  685.    list->base.gadget = gad;
  686.  
  687.    reset_list_object(list, -1);
  688.  
  689.    return(uly+global.listextra);
  690. }
  691.  
  692. /***********************************************************************************
  693.  * Procedure: layout_gadgets
  694.  * Synopsis:  gadlist = layout_gadgets(objlist, group, ulx, yly, width);
  695.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  696.  *            of gadgets.
  697.  ***********************************************************************************/
  698. struct GADLIST *layout_gadgets(struct G_OBJECT *objlist,
  699.                                int group,
  700.                                int ulx, int uly,
  701.                                int width
  702.                               )
  703. {
  704.    struct Gadget *gad;
  705.    struct IntuiText *itext, *itext1;
  706.    int ilen;
  707.    struct G_OBJECT *obj;
  708.    struct GADLIST *gadlist;
  709.  
  710.    gadlist = (struct GADLIST *)get_mem(sizeof(struct GADLIST));
  711.    if (gadlist == NULL) return(NULL);
  712.  
  713.    /* First we need to lay out the gadgets on the left side of the window */
  714.    for(obj = objlist; obj != NULL; obj = obj->next)
  715.    {
  716.       /* Create a gadget structure and an associated intuitext structure to be */
  717.       /* Layed out on the screen                                               */
  718.       gad = create_gadget(gadlist, obj, ulx, uly, width);
  719.  
  720.       if (gad == NULL) return(gadlist);
  721.  
  722.       itext = (struct IntuiText *)(gad+1);
  723.  
  724.       uly += gad->Height;
  725.  
  726.       ilen = IntuiTextLength(itext);
  727.       switch(obj->class)
  728.       {
  729.          case CLASS_STRING:
  730.             gad->LeftEdge   += global.titsize[group];
  731.             gad->Width       = global.cycsize[group];
  732.             itext->LeftEdge  = -ilen;
  733.             setup_string_gadget(gad, CLASS_STRING);
  734.             break;
  735.  
  736.          case CLASS_GROUP:
  737.             gad->GadgetRender = global.cycborder[group];
  738.             gad->GadgetType   = BOOLGADGET;
  739.             gad->Width        = global.cycsize[group];
  740.             gad->LeftEdge    += global.titsize[group] / 2;
  741.             itext->LeftEdge   = (CYC_ICON_WIDTH+gad->Width-ilen)/2;
  742.             uly  += MARGIN_TOP;
  743.             break;
  744.  
  745.          case CLASS_CYCLE:
  746.             gad->GadgetRender = global.cycborder[group];
  747.             gad->GadgetType = BOOLGADGET;
  748.             gad->LeftEdge   += global.titsize[group];
  749.             gad->Width       = global.cycsize[group];
  750.             itext->LeftEdge  = -ilen;
  751.             itext1 = (struct IntuiText *)get_mem(sizeof(struct IntuiText));
  752.             if (itext1 == NULL) return(gadlist);
  753.             itext1->FrontPen  = 1;
  754.             itext1->BackPen   = 0;
  755.             itext1->DrawMode  = JAM1;
  756.             itext1->LeftEdge  = 0;
  757.             itext1->TopEdge   = 3;
  758.             itext1->ITextFont = &global.ri.TextAttr;
  759.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  760.             itext1->NextText  = NULL;
  761.             itext1->LeftEdge  = (CYC_ICON_WIDTH+gad->Width-IntuiTextLength(itext1))/2;
  762.  
  763.             itext->NextText   = itext1;
  764.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  765.             break;
  766.  
  767.          case CLASS_CHECK:
  768.             gad->GadgetType   = BOOLGADGET;
  769.             gad->Width        = CHECK_WIDTH;
  770.             gad->Height       = CHECK_HEIGHT;
  771.             gad->Flags        = GADGHIMAGE;
  772.             if (obj->state)   gad->Flags |= SELECTED;
  773.             gad->Activation  |= TOGGLESELECT;
  774.             gad->GadgetRender = global.checkborder[0];
  775.             gad->SelectRender = global.checkborder[1];
  776.             itext->LeftEdge  += CHECK_WIDTH + 4;
  777.             break;
  778.  
  779.          case CLASS_LIST:
  780.             uly = setup_list_object(gadlist, gad);
  781.             if (uly <= 0) return(gadlist);
  782.             break;
  783.  
  784.          default:
  785.             gad->GadgetType = BOOLGADGET;
  786.             break;
  787.       }
  788.    }
  789.    return(gadlist);
  790. }
  791.  
  792. /***********************************************************************************
  793.  * Procedure: build_border
  794.  * Synopsis:  Border = build_border(width, height, mode)
  795.  * Purpose:   Build an return a set of drawing vectors that represent a button of
  796.  *            width and height.  Mode can be either MODE_OUT or MODE_IN
  797.  ***********************************************************************************/
  798. struct Border *build_border(int width,
  799.                             int height,
  800.                             int mode
  801.                            )
  802. {
  803.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  804.    /*                                                                             */
  805.    /* Select the colors based on the rendering mode.  For an out box, we will use */
  806.    /* the lighter color on the upper and left sides and the darker color on the   */
  807.    /* other two sides.  In an in box, the choice is reversed.                     */
  808.    /*   (x,y)                                                5                    */
  809.    /*   1****************************************************.2                   */
  810.    /*    **4                                               3..                    */
  811.    /*    **                                                 ..                    */
  812.    /*    **                                                 ..                    */
  813.    /*    **                                                 ..                    */
  814.    /*    **                                                 ..                    */
  815.    /*    **3 5                                             4..                    */
  816.    /*   2*....................................................1                   */
  817.    /*                                                       (x+width, y+height)   */
  818.    /* 0.       0,    0    10.   wd,   ht                                          */
  819.    /* 2.       0,   ht    12.   wd,    0                                          */
  820.    /* 4.       1, ht-1    14. wd-1,    1                                          */
  821.    /* 6.       1,    0    16. wd-1,   ht                                          */
  822.    /* 8.    wd-1,    0    18.    1,   ht                                          */
  823.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  824.  
  825.    struct Border *border, *border1;
  826.    short *vecs;
  827.    int i;
  828.  
  829.    static short inits[] = { 0, 0,   0, 0,   1,-1,   1, 0,  -1, 0,
  830.                             0, 0,   0, 0,  -1, 1,  -1, 0,   1, 0};
  831.  
  832. #define VEC_COUNT 5
  833. #define SINGLEUNIT (sizeof(struct Border)+sizeof(inits))
  834.  
  835.    width--;
  836.    height--;
  837.    border = (struct Border *)get_mem(2*SINGLEUNIT);
  838.    if (border == NULL) return(NULL);
  839.  
  840.    border1 = border+1;
  841.    vecs = (short *)(border+2);
  842.    border->NextBorder = border1;
  843.    border->DrawMode   = JAM1;
  844.    border->Count      = VEC_COUNT;
  845.    border->XY         = vecs;
  846.  
  847.    border1->DrawMode  = JAM1;
  848.    border1->Count     = VEC_COUNT;
  849.    border1->XY        = vecs + (2*VEC_COUNT);
  850.  
  851.    memcpy((char *)vecs, (char *)inits, sizeof(inits));
  852.    for(i = 8; i < 17; i += 2) vecs[i] += width;
  853.    vecs[3]  += height;
  854.    vecs[5]  += height;
  855.    vecs[11] += height;
  856.    vecs[17] += height;
  857.    vecs[19] += height;
  858.  
  859.    if (mode == MODE_OUT)
  860.    {
  861.       border1->FrontPen = global.ri.Shadow;
  862.       border->FrontPen = global.ri.Highlight;
  863.    }
  864.    else
  865.    {
  866.       border1->FrontPen = global.ri.Highlight;
  867.       border->FrontPen  = global.ri.Shadow;
  868.    }
  869.    return(border);
  870. }
  871.  
  872. /***********************************************************************************
  873.  * Procedure: init_gad_sizes
  874.  * Synopsis:  rc = init_gad_sizes();
  875.  * Purpose:   Calculate and initialize all the imagery structures
  876.  ***********************************************************************************/
  877. int init_gad_sizes()
  878. {
  879.    struct G_GROUP     *groups;
  880.    int i;
  881.    int width, height, fudgesize;
  882.    struct Border *border;
  883.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  884.    /*                                                   */
  885.    /*              11111111                11111111     */
  886.    /*    012345678901234567      012345678901234567     */
  887.    /*    =================#      =================# 0   */
  888.    /*    ||......23......##      ||..18......54..## 1   */
  889.    /*    ||......##......##      ||..##......##..## 2   */
  890.    /*    ||.....####.....##      ||...##....##...## 3   */
  891.    /*    ||....##76##....##      ||....##76##....## 4   */
  892.    /*    ||...##....##...##      ||.....####.....## 5   */
  893.    /*    ||..##......##..##      ||......##......## 6   */
  894.    /*    ||..18......54..##      ||......23......## 7   */
  895.    /*    |#################      |################# 8   */
  896.    /*                                                   */
  897.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  898.    static short Up_Vectors[] = { 4,6,  8,2,  9,2, 13,6, 12,6,  9,3,  8,3,  5,6 };
  899.    static short Dn_Vectors[] = { 4,2,  8,6,  9,6, 13,2, 12,2,  9,5,  8,5,  5,2 };
  900.  
  901.    /* * * * * * * * * * * * * * * * * * */
  902.    /*              11111111112222       */
  903.    /*    012345678901234567890134       */
  904.    /*    ========================== 0   */
  905.    /*    ||.....7.....8..........   1   */
  906.    /*    ||.....#######......#|..   2   */
  907.    /*    ||...5##.....##d....#|..   3   */
  908.    /*    ||....##.....##.....#|..   4   */
  909.    /*    ||....##..a######b..#|..   5   */
  910.    /*    ||....##....####....#|..   6   */
  911.    /*    ||....##....9##c....#|..   7   */
  912.    /*    ||....##............#|..   8   */
  913.    /*    ||...4##6...0##1....#|..   9   */
  914.    /*    ||.....#######......#|..   10  */
  915.    /*    ||.....3.....2..........   11  */
  916.    /*    |########################  12  */
  917.    /*                                   */
  918.    /* * * * * * * * * * * * * * * * * * */
  919.    static short Cycle_Vectors[] = { 13, 9,  14, 9,  13,10,   7,10,   6, 9,
  920.                                      6, 3,   7, 9,   7, 2,  13, 2,  13, 7,
  921.                                     11, 5,  16, 5,  14, 7,  14, 3, };
  922.    static short Cycle_Line1[]   = { 20, 2,  20,11};
  923.    static short Cycle_Line2[]   = { 21, 2,  21,11};
  924.  
  925.    static short Check_Vectors[] = { 19, 2,  17, 2,  11, 8,   8, 5,   7, 5,
  926.                                     10, 8,   9, 5,  12, 8,  18, 2 };
  927.  
  928.    /* Make two passes attempting to layout the items.  The first time we will use */
  929.    /* Whatever the prevailing font is.  If this doesn't work, we will switch to a */
  930.    /* Simple TOPAZ80 and try again.  Only if that fails will we give up.          */
  931.    for(i = 2; i >= 0; i--)
  932.    {
  933.       int dwid,nwid;
  934.       global.cycsize[0] = global.cycsize[1] = 0;
  935.       global.titsize[0] = global.titsize[1] = 0;
  936.       global.stxtwid = text_width("0");
  937.       nwid = text_width(global.button[BUTTON_NEW].title);
  938.       dwid = text_width(global.button[BUTTON_DEL].title);
  939.       global.lgadwid = (dwid > nwid ? dwid : nwid) + PROP_WIDTH + 3*DVBAR;
  940.  
  941.       fudgesize = 0;
  942.       get_cycle_sizes(global.objects, global.titsize, global.cycsize, &fudgesize);
  943.       if ((global.cycsize[0] + global.titsize[0]) < fudgesize)
  944.          global.cycsize[0] = fudgesize - global.titsize[0];
  945.  
  946.       fudgesize = 0;
  947.       for(groups = global.groups; groups != NULL;
  948.           groups = (struct G_GROUP *)groups->base.next)
  949.       {
  950.          get_cycle_sizes(groups->objects, global.titsize+1, global.cycsize+1,
  951.                          &fudgesize);
  952.          if (global.cycsize[1] < (text_width(groups->base.title)
  953.                                     + CYC_ICON_WIDTH + 2*DVBAR))
  954.             global.cycsize[1] = text_width(groups->base.title)
  955.                                     + CYC_ICON_WIDTH + 2*DVBAR;
  956.       }
  957.       if ((global.cycsize[1] + global.titsize[1]) < fudgesize)
  958.          global.cycsize[1] = fudgesize - global.titsize[1];      
  959.  
  960.       global.iheight = global.ri.TextAttr.ta_YSize+DHBAR;
  961.       if (global.iheight < global.ri.FontSize)
  962.          global.iheight = global.ri.FontSize;
  963.       if (i)
  964.       {
  965.          global.iheight += 4; /* Account for decent margins on the rendering */
  966.          global.eheight = global.ri.FontSize + 2*DHBAR;
  967.          global.listextra = 0;
  968.       }
  969.       else
  970.       {
  971.          global.iheight += 2; /* Account for decent margins on the rendering */
  972.          global.eheight = global.ri.FontSize + DHBAR + HBAR;
  973.          global.listextra = 1;
  974.       }
  975.  
  976.       /* We have the totals for everything, let's figure out how */
  977.       /* big the final thing is going to be.                     */
  978.       height = ((global.maxsize+1)*global.iheight) +
  979.                2*global.listextra +
  980.                global.ri.WindowTitle +
  981.                global.ri.WindowBottom + MARGIN_MID;
  982.       width  = global.cycsize[0]+global.cycsize[1] +
  983.                global.titsize[0]+global.titsize[1] +
  984.                global.ri.WindowLeft +
  985.                global.ri.WindowRight +
  986.                MARGIN_SEP + MARGIN_LEFT + MARGIN_RIGHT;
  987.  
  988.       if ((height <= global.ri.ScreenHeight) &&
  989.           (width  <= global.ri.ScreenWidth)) break;
  990.  
  991.       if (i==0)
  992.       {
  993.          /* We couldn't fit what they wanted on the screen, so error out with */
  994.          /* A message indicating the problem.  We really shouldn't see this   */
  995.          /* happen much, but at least account for it.                         */
  996.          sprintf(global.title, "Bad Layout W:%d>%d H:%d>%d",
  997.                                 width, global.ri.ScreenWidth,
  998.                                 height, global.ri.ScreenHeight);
  999.          return(1);
  1000.       }
  1001.       /* Set up so we try with Topaz 80 as our default font the second time around */
  1002.       global.ri.TextAttr = TOPAZ80;
  1003.    }
  1004.  
  1005.    /* Now we have calculated sizes for the objects, layout the border structures */
  1006.    for(i = 0; i < 2; i++)
  1007.    {
  1008.       /* Create a border for the cycle gadgets */
  1009.       global.cycborder[i] = build_border(global.cycsize[i],
  1010.                                           global.iheight, MODE_OUT);
  1011.       /* We also need to put in the vectors for the cycle picture */
  1012.       border = (struct Border *)get_mem(4*sizeof(struct Border));
  1013.       if (border == NULL) return(1);
  1014.  
  1015.       border[0].NextBorder = border+1;
  1016.       border[1].NextBorder = border+2;
  1017.       border[2].NextBorder = global.cycborder[i];
  1018.       global.cycborder[i] = border;
  1019.  
  1020.       border[0].DrawMode = JAM1;
  1021.       border[0].Count  = sizeof(Cycle_Vectors)/(2*sizeof(short));
  1022.       border[0].XY = Cycle_Vectors;
  1023.       border[0].FrontPen = 1;
  1024.  
  1025.       border[1].DrawMode = JAM1;
  1026.       border[1].Count  = sizeof(Cycle_Line1)/(2*sizeof(short));
  1027.       border[1].XY = Cycle_Line1;
  1028.       border[1].FrontPen = global.ri.Shadow;
  1029.  
  1030.       border[2].DrawMode = JAM1;
  1031.       border[2].Count  = sizeof(Cycle_Line2)/(2*sizeof(short));
  1032.       border[2].XY = Cycle_Line2;
  1033.       border[2].FrontPen = global.ri.Highlight;
  1034.  
  1035.       global.checkborder[i] = border+3;
  1036.       border[3].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
  1037.       border[3].DrawMode = JAM1;
  1038.       border[3].Count = sizeof(Check_Vectors)/(2*sizeof(short));
  1039.       border[3].XY = Check_Vectors;
  1040.       border[3].FrontPen = i;
  1041.    }
  1042.  
  1043.    /* Adjust the height of the cycle vectors to the current height */
  1044.    /* See the picture above for these values.  Yes, they are hard  */
  1045.    /* coded magic values, but equates for them don't make a lot of */
  1046.    /* sense in a situation like this.                              */
  1047.    for(i = 0; i < 0x0d; i++)
  1048.    {
  1049.       int extra;
  1050.  
  1051.       extra = global.iheight - 13;
  1052.       if (i > 8)
  1053.       {
  1054.          extra >>= 1;
  1055.       }
  1056.       else if ((i > 6) || (i == 5))
  1057.       {
  1058.          extra = 0;
  1059.       }
  1060.  
  1061.       Cycle_Vectors[1+i*2] += extra;
  1062.    }
  1063.  
  1064.    Cycle_Line2[3] = Cycle_Line1[3] = (global.iheight - 1) - DHBAR;
  1065.  
  1066.    {
  1067.       int bheight;
  1068.       bheight = (MAX_LIST*global.eheight) - (2*ARR_HEIGHT) + global.listextra;
  1069.       border = build_border(PROP_WIDTH, bheight, MODE_OUT);
  1070.       if (border == NULL) return(1);
  1071.  
  1072.       border->TopEdge -= bheight;
  1073.       border->NextBorder->TopEdge -= bheight;
  1074.    }
  1075.  
  1076.    global.arrowborder[0].NextBorder = build_border(PROP_WIDTH, ARR_HEIGHT, MODE_OUT);
  1077.    global.arrowborder[1].NextBorder = border;
  1078.    border->NextBorder->NextBorder = global.arrowborder[0].NextBorder;
  1079.  
  1080.    global.arrowborder[0].DrawMode = JAM1;
  1081.    global.arrowborder[0].Count  = sizeof(Dn_Vectors)/(2*sizeof(short));
  1082.    global.arrowborder[0].XY = Dn_Vectors;
  1083.    global.arrowborder[0].FrontPen = 1;
  1084.  
  1085.    global.arrowborder[1].DrawMode = JAM1;
  1086.    global.arrowborder[1].Count  = sizeof(Up_Vectors)/(2*sizeof(short));
  1087.    global.arrowborder[1].XY = Up_Vectors;
  1088.    global.arrowborder[1].FrontPen = 1;
  1089.  
  1090.    /* Everything worked out fine, let us set the height of the window */
  1091.    global.width = width;
  1092.    global.height = height;
  1093.  
  1094.    /* Now sizes for special string gadgets            */
  1095.    global.titsize[2] = text_width(global.text[TEXT_FILEREQ]);
  1096.    global.cycsize[2] = global.width - global.ri.WindowLeft
  1097.                         - global.ri.WindowRight - 100;
  1098.  
  1099.    return(0);
  1100. }
  1101.  
  1102. /***********************************************************************************
  1103.  * Procedure: get_cycle_sizes
  1104.  * Synopsis:  get_cycle_sizes(objlist, &titsize, &cycsize)
  1105.  * Purpose:   Calculate the base sizes for different types of objects.
  1106.  *            We need to calculate the width for CYCLE titles and size for cycles
  1107.  *            Everything else has a fixed size to be used anyway.
  1108.  ***********************************************************************************/
  1109. void get_cycle_sizes(struct G_OBJECT *objlist,
  1110.                     int *titsize,
  1111.                     int *cycsize,
  1112.                     int *fudgesize)
  1113. {
  1114.    int wid;
  1115.    struct G_OBJECT *obj;
  1116.    struct G_CYCLE *cyc;
  1117.    struct G_VALUE *val;
  1118.  
  1119. /*
  1120.    *titsize -= DVBAR;
  1121.    *cycsize -= CYC_ICON_WIDTH+DVBAR;
  1122. */
  1123.  
  1124.    /* First we need to lay out the gadgets on the left side of the window */
  1125.    for(obj = objlist; obj != NULL; obj = obj->next)
  1126.    {
  1127.       switch(obj->class)
  1128.       {
  1129.          case CLASS_CYCLE:
  1130.             /* go through and get all the cycle values */
  1131.             cyc = (struct G_CYCLE *)obj;
  1132.             set_cyc_state(cyc, cyc->values);
  1133.             for(val = cyc->values; val != NULL; val = val->next)
  1134.             {
  1135.                wid = text_width(val->title) + CYC_ICON_WIDTH+DVBAR;
  1136.                if (val->string)
  1137.                {
  1138.                   int num;
  1139.                   num = string_width(val->option, 3);
  1140.                   wid += (global.stxtwid * num) + DVBAR;
  1141.                }
  1142.                if (wid > *cycsize) *cycsize = wid;
  1143.             }
  1144.             wid = text_width(obj->title) + DVBAR;
  1145.             if (wid > *titsize) *titsize = wid;
  1146.             break;
  1147.          case CLASS_STRING:
  1148.             wid = text_width(obj->title);
  1149.             if (wid > *titsize) *titsize = wid;
  1150.             /* provide a reasonable default string entry area */
  1151.             wid = string_width(((struct G_STRING *)obj)->option, 10);
  1152.             wid = wid * global.stxtwid + 2*DVBAR;
  1153.             if (wid > *cycsize) *cycsize = wid;
  1154.             break;
  1155.          case CLASS_LIST:
  1156.             wid = text_width(obj->title);
  1157.             if (wid > *fudgesize) *fudgesize = wid;
  1158.             wid = string_width(((struct G_LIST *)obj)->option, 10);
  1159.             wid = wid * global.stxtwid + global.lgadwid;
  1160.             if (wid > *fudgesize) *fudgesize = wid;
  1161.             break;
  1162.          case CLASS_CHECK:
  1163.             wid = text_width(obj->title) + CHECK_WIDTH + 2*DVBAR;
  1164.             if (wid > *fudgesize) *fudgesize = wid;
  1165.             break;
  1166.       }
  1167.    }
  1168. /*
  1169.    *titsize += DVBAR;
  1170.    *cycsize += CYC_ICON_WIDTH+DVBAR;
  1171. */
  1172. }
  1173.  
  1174. /***********************************************************************************
  1175.  * Procedure: text_width
  1176.  * Synopsis:  len = text_width(str)
  1177.  * Purpose:   Return the rendered width of a given string
  1178.  ***********************************************************************************/
  1179. int text_width(char *str
  1180.               )
  1181. {
  1182.    struct IntuiText itext;
  1183.  
  1184.    itext.FrontPen  = 1;
  1185.    itext.BackPen   = 0;
  1186.    itext.DrawMode  = JAM1;
  1187.    itext.LeftEdge  = 0;
  1188.    itext.TopEdge   = 1;
  1189.    itext.ITextFont = &global.ri.TextAttr;
  1190.    itext.NextText  = NULL;
  1191.    itext.IText     = str;
  1192.  
  1193.    return(IntuiTextLength(&itext));
  1194. }
  1195.  
  1196. /**********************************************************************************
  1197.  * Procedure: string_width
  1198.  * Synopsis:  len = string_width(str)
  1199.  * Purpose:   Return the size of a string specification %ns, default n = 3
  1200.  *********************************************************************************/
  1201. int string_width(char *str, int def_width)
  1202. {
  1203.    char *p;
  1204.    int num;
  1205.  
  1206.    p = strchr(str, '%');
  1207.    num = 0;
  1208.    if (p)
  1209.    {
  1210.       p++;
  1211.       while ((*p >= '0') && (*p <= '9'))
  1212.          num = (num * 10) + *p++ - '0';
  1213.    }
  1214.    
  1215.    if (num <= 0) num = def_width;
  1216.    return (num + 1);
  1217. }
  1218.